import asyncio
from fastapi import APIRouter, Depends, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from jose import jwt, JWTError
from sqlalchemy.orm import Session
from captcha.image import ImageCaptcha
import random, string, re
from . import models, utils
from auth.utils import get_current_user_info, SECRET_KEY, ALGORITHM
from devices.models import Device
from datetime import datetime, timedelta, timezone
from .db import SessionLocal
from logging_config import setup_logging
from cache.redis_client import redis_cache




logger=setup_logging()
router = APIRouter()
templates = Jinja2Templates(directory="templates")
# ---------------- 数据库连接 ----------------
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
# ----------------在注册函数中，替换所有的医生列表查询----------------
def get_doctors_cached(db: Session):
    """获取医生列表（使用缓存）"""
    if redis_cache.is_available():
        cached = redis_cache.get_doctor_list()
        if cached:
            return [type('Doctor', (), d) for d in cached]  # 转换为对象

    # 缓存未命中，从数据库查询
    doctors = db.query(models.User).filter(models.User.role == "doctor").all()

    # 更新缓存
    if redis_cache.is_available() and doctors:
        doctors_data = [{"id": d.id, "username": d.username} for d in doctors]
        redis_cache.set_doctor_list(doctors_data)

    return doctors
# ---------------- 时区修改 ----------------
CST = timezone(timedelta(hours=8))
def now_cst():
    """返回当前北京时间（带时区信息）"""
    return datetime.now(CST)
# ---------------- 生成验证码 ----------------
@router.get("/captcha")
def get_captcha(request: Request):
    """生成验证码图片"""
    image = ImageCaptcha(width=120, height=40)
    code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
    request.session["captcha"] = code.lower()
    data = image.generate(code)
    return StreamingResponse(data, media_type="image/png")
# ---------------- 注册页面 ----------------
@router.get("/register", response_class=HTMLResponse)
def register_page(request: Request, db: Session = Depends(get_db)):
    doctors = get_doctors_cached(db)
    return templates.TemplateResponse("register.html", {"request": request, "doctors": doctors, "role": ""})
# ---------------- 注册 ----------------
@router.post("/register")
async def register_user(request: Request, db: Session = Depends(get_db)):
    form = await request.form()
    username = form.get("username", "").strip()
    email = form.get("email", "").strip() or None
    phone = form.get("phone", "").strip()
    password = form.get("password", "").strip()
    confirm_password = form.get("confirm_password", "").strip()
    doctor_id_raw = form.get("doctor_id", "").strip() or None  # 保留原字符串形式

    # ---------- 用户名长度校验 ----------
    if len(username) < 1 or len(username) > 20:
        doctors = get_doctors_cached(db)
        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": "用户名长度必须在 1 到 20 个字符之间！",
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ---------- 密码长度校验 ----------
    if len(password) < 6 or len(password) > 13:
        doctors = get_doctors_cached(db)
        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": "密码长度必须在 6 到 13 个字符之间！",
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ---------- 确认密码匹配 ----------
    if password != confirm_password:
        doctors = get_doctors_cached(db)
        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": "两次密码输入不一致，请重试",
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ---------- 手机号格式 ----------
    if not re.match(r"^1[3-9]\d{9}$", phone):
        doctors = get_doctors_cached(db)
        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": "手机号格式错误，请输入中国大陆手机号",
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ---------- 邮箱格式 ----------
    if email and not re.match(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$", email):
        doctors = get_doctors_cached(db)
        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": "邮箱格式不正确，请输入有效邮箱地址",
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ========== 优化点1: 提前开始密码哈希（在查询数据库的同时进行） ==========
    # 使用 asyncio.create_task 让哈希计算和数据库查询并行进行
    hash_task = asyncio.ensure_future(utils.hash_password_async(password))

    # ---------- 优化点2: 合并唯一性检查（一次查询） ----------
    from sqlalchemy import or_

    # 构建查询条件
    conditions = [models.User.username == username, models.User.phone == phone]
    if email:
        conditions.append(models.User.email == email)

    # 一次性查询所有可能冲突的用户
    existing_users = db.query(models.User).filter(or_(*conditions)).all()

    msg = None
    if existing_users:
        for user in existing_users:
            if user.username == username:
                msg = "用户名已存在"
                break
            elif user.phone == phone:
                msg = "手机号已被使用"
                break
            elif email and user.email == email:
                msg = "邮箱已被使用"
                break

    if msg:
        doctors = get_doctors_cached(db)
        # 取消哈希任务
        hash_task.cancel()
        try:
            await hash_task
        except asyncio.CancelledError:
            pass

        return templates.TemplateResponse("register.html", {
            "request": request,
            "msg": msg,
            "username": username, "email": email, "phone": phone,
            "doctors": doctors, "doctor_id": doctor_id_raw
        })

    # ---------- 医生验证 ----------
    doctor_obj = None
    if doctor_id_raw not in [None, "", "null"]:
        # 严格验证 doctor_id 必须是纯数字
        if not doctor_id_raw.isdigit():
            doctors = get_doctors_cached(db)
            # 取消哈希任务
            hash_task.cancel()
            try:
                await hash_task
            except asyncio.CancelledError:
                pass

            return templates.TemplateResponse("register.html", {
                "request": request,
                "msg": "医生ID格式错误，请选择正确的医生",
                "username": username, "email": email, "phone": phone,
                "doctors": doctors, "doctor_id": doctor_id_raw
            })

        doctor_id_int = int(doctor_id_raw)
        doctor_obj = db.query(models.User).filter(
            models.User.id == doctor_id_int,
            models.User.role == "doctor"
        ).first()

        if not doctor_obj:
            doctors = get_doctors_cached(db)
            # 取消哈希任务
            hash_task.cancel()
            try:
                await hash_task
            except asyncio.CancelledError:
                pass

            return templates.TemplateResponse("register.html", {
                "request": request,
                "msg": "不存在该医生，请重新选择",
                "username": username, "email": email, "phone": phone,
                "doctors": doctors, "doctor_id": doctor_id_raw
            })

    # ========== 优化点3: 等待哈希完成（此时哈希可能已经完成） ==========
    hashed_pw = await hash_task

    # ---------- 数据入库 ----------
    new_user = models.User(
        username=username,
        password=hashed_pw,
        email=email,
        phone=phone,
        role="user",
        doctor_id=doctor_obj.id if doctor_obj else None  # 确保 doctor_id 不会丢
    )
    db.add(new_user)
    db.commit()
    logger.info(f"用户{username}注册成功")
    # ---------- 注册成功 ----------
    return templates.TemplateResponse("login.html", {
        "request": request,
        "msg": "注册成功，请登录！",
        "username": username
    })
# ---------------- 登录页面 ----------------
@router.get("/login", response_class=HTMLResponse)
def login_page(request: Request, msg: str = ""):
    return templates.TemplateResponse("login.html", {"request": request, "msg": msg})
# ---------------- 登录 ----------------
# 是否启用验证码验证（开发时可关闭）
DISABLE_CAPTCHA = True  # True = 禁用验证码，False = 开启验证
@router.post("/login")
async def login_user(  # 改为 async
        request: Request,
        username: str = Form(...),
        password: str = Form(...),
        captcha: str = Form(None),
        db: Session = Depends(get_db)
):
    # 若未禁用验证码，则进行校验
    if not DISABLE_CAPTCHA:
        session_code = request.session.get("captcha")
        if not session_code:
            return templates.TemplateResponse(
                "login.html",
                {
                    "request": request,
                    "msg": "验证码已过期，请刷新后重试",
                    "username": username,
                    "password": password
                }
            )
        if captcha.strip().lower() != session_code.strip().lower():
            return templates.TemplateResponse(
                "login.html",
                {
                    "request": request,
                    "msg": "验证码错误，请重试",
                    "username": username,
                    "password": password
                }
            )

    # ========== 优化：先尝试从缓存读取用户 ==========
    user_data = None
    if redis_cache.is_available():
        user_data = redis_cache.get_user(username)

    if user_data:
        # 从缓存恢复用户对象（创建一个类似 User 模型的对象）
        class CachedUser:
            def __init__(self, data):
                self.id = data["id"]
                self.username = data["username"]
                self.password = data["password"]
                self.role = data["role"]

        user = CachedUser(user_data)
        logger.info(f"用户{username}从缓存读取")
    else:
        # 缓存未命中，从数据库查询
        user = db.query(models.User).filter(models.User.username == username).first()
        if not user:
            return templates.TemplateResponse(
                "login.html",
                {
                    "request": request,
                    "msg": "用户不存在",
                    "username": username,
                    "password": password
                }
            )

        # 更新缓存
        if redis_cache.is_available():
            redis_cache.set_user(username, {
                "id": user.id,
                "username": user.username,
                "password": user.password,
                "role": user.role
            })
            logger.info(f"用户{username}已缓存到Redis")

    # ========== 优化：使用异步密码验证 ==========
    if not await utils.verify_password_async(password, user.password):
        return templates.TemplateResponse(
            "login.html",
            {
                "request": request,
                "msg": "密码错误",
                "username": username,
                "password": password
            }
        )

    # ---------- 登录成功 ----------
    logger.info(f"用户{username}登录成功")
    token = utils.create_access_token({"sub": user.username, "role": user.role})

    # 这里改为 302（原来是 303），防止 requests 丢失 Cookie
    # 这样 pytest、requests、浏览器 的行为完全一致
    response = RedirectResponse(url="/", status_code=302)
    response.set_cookie(
        key="access_token",
        value=f"Bearer {token}",
        httponly=True
    )

    return response
# ---------------- 主页面 ----------------
@router.get("/", response_class=HTMLResponse)
def home(request: Request):
    token_cookie = request.cookies.get("access_token")
    username, role = None, None
    if token_cookie:
        try:
            token = token_cookie.split(" ")[1]
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            username = payload.get("sub")
            role = payload.get("role", "user")
        except JWTError:
            pass
    if not username:
        return RedirectResponse(url="/login", status_code=303)

    return templates.TemplateResponse("dashboard.html", {
        "request": request, "username": username, "role": role, "active_tab": "home"
    })

# ---------------- 登出 ----------------
@router.get("/logout")
def logout():
    response = RedirectResponse("/login", status_code=303)

    # 获取当前 CST 时间
    cst_now = now_cst()

    # 转换为 UTC
    utc_time = cst_now.astimezone(timezone.utc)

    # 设置 cookie 过期
    response.set_cookie(
        "access_token",
        "",
        expires=utc_time.strftime("%a, %d %b %Y %H:%M:%S GMT")
    )

    # 再保险：直接 delete_cookie
    response.delete_cookie("access_token")

    return response

# ---------------- 设备实时状态统计 ----------------
@router.get("/admin/device_stats")
def admin_device_stats(request: Request,db: Session = Depends(get_db)):
    username,role=get_current_user_info(request)
    if role not in ["admin","superadmin"]:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "权限不足",
            "message": f"当前账户（{username}）没有访问用户管理页的权限。",
            "redirect_url": "/",
            "status": "error"
        })
    logger.info(f"{username}查看设备实时状态统计界面")
    """返回当天24小时内的设备在线数量统计"""
    now = now_cst()
    current_hour = now.hour
    data_points = []

    current_online = db.query(Device).filter(Device.online == True).count()

    for hour in range(24):
        if hour <= current_hour:
            fluctuation = random.randint(-2, 100)
            count = max(0, current_online + fluctuation)
        else:
            count = 0
        data_points.append({"hour": f"{hour:02d}:00", "count": count})

    return JSONResponse(content=data_points)


#------- 用户管理（管理员/超级管理员） ----------------
@router.get("/users", response_class=HTMLResponse)
def users_page(
    request: Request,
    db: Session = Depends(get_db),
    q: str = None,
    msg: str = None,
    role_filter: str = None,
    page: int = 1                     # 新增分页参数
):
    """管理员/超级管理员查看用户列表 + 分页 + 搜索 + 筛选"""
    username, role = get_current_user_info(request)

    # 登录验证
    if not username:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "未登录",
            "message": "请先登录后再进行操作。",
            "redirect_url": "/login",
            "status": "error"
        })

    # 权限检查
    if role not in ["admin", "superadmin"]:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "权限不足",
            "message": f"当前账户（{username}）没有访问用户管理页的权限。",
            "redirect_url": "/",
            "status": "error"
        })
    logger.info(f"{username}查看用户管理界面")
    # ----------- 构建基础查询 -----------
    query = db.query(models.User)

    # 权限约束
    if role == "superadmin":
        query = query.filter(
            models.User.username != username,
            models.User.role != "superadmin"
        )
        allowed_roles = ["user", "doctor", "admin"]

    elif role == "admin":
        query = query.filter(
            models.User.role.notin_(["admin", "superadmin"]),
            models.User.username != username
        )
        allowed_roles = ["user", "doctor"]

    # 搜索
    if q:
        query = query.filter(models.User.username.contains(q))

    # 角色筛选
    if role_filter and role_filter != "all":
        query = query.filter(models.User.role == role_filter)

    # ----------- 分页逻辑 -----------
    PER_PAGE = 10
    total = query.count()
    total_pages = max((total + PER_PAGE - 1) // PER_PAGE, 1)

    # 页码修正
    if page < 1:
        page = 1
    if page > total_pages:
        page = total_pages

    # 获取分页数据
    users = (
        query.order_by(models.User.id)
        .offset((page - 1) * PER_PAGE)
        .limit(PER_PAGE)
        .all()
    )

    # ----------- 返回模板 -----------
    return templates.TemplateResponse("dashboard.html", {
        "request": request,
        "username": username,
        "role": role,
        "users": users,

        "search_q": q or "",
        "role_filter": role_filter or "all",
        "allowed_roles": allowed_roles,

        "msg": msg,
        "active_tab": "users",

        # 传递分页参数
        "current_page": page,
        "total_pages": total_pages
    })

# ---------------- 修改用户角色 ----------------
@router.post("/users/update_role")
def update_user_role(
    request: Request,
    username: str = Form(...),
    role: str = Form(...),
    db: Session = Depends(get_db)
):
    """修改用户角色：支持权限限制、设备清理、患者解绑、唯一超级管理员限制"""
    # 当前用户权限验证
    current_name, current_role = get_current_user_info(request)

    # 未登录 → 提示登录信息
    if not current_name:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "未登录",
            "message": "请先登录后再进行操作。",
            "redirect_url": "/login",
            "status": "error"
        })

    # 权限不足 → 普通用户禁止访问
    if current_role not in ["admin", "superadmin"]:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "权限不足",
            "message": f"当前账户（{current_name}）没有修改用户角色的权限。",
            "redirect_url": "/",
            "status": "error"
        })

    # 查询目标用户
    user = db.query(models.User).filter(models.User.username == username).first()
    if not user:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "操作失败",
            "message": f"未找到用户名为「{username}」的用户。",
            "redirect_url": "/users",
            "status": "error"
        })

    # 超级管理员不可修改
    if user.role == "superadmin":
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "操作失败",
            "message": "无法修改超级管理员的角色。",
            "redirect_url": "/users",
            "status": "error"
        })

    # 管理员限制：禁止分配管理员或超级管理员角色
    if current_role == "admin" and role in ["admin", "superadmin"]:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "操作失败",
            "message": "管理员无权分配管理员或超级管理员角色",
            "redirect_url": "/users",
            "status": "error"
        })

    # 3-补充️⃣ 管理员不能修改管理员或超级管理员用户
    if current_role == "admin" and user.role in ["admin", "superadmin"]:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "操作失败",
            "message": "管理员无权分配管理员或超级管理员角色",
            "redirect_url": "/users",
            "status": "error"
        })

    # 限制：仅允许一个超级管理员
    if role == "superadmin":
        existing_superadmin = db.query(models.User).filter(models.User.role == "superadmin").first()
        if existing_superadmin and existing_superadmin.username != username:
            return templates.TemplateResponse("success.html", {
                "request": request,
                "title": "操作失败",
                "message": f"系统中已存在超级管理员「{existing_superadmin.username}」，不能再创建第二个。",
                "redirect_url": "/users",
                "status": "error"
            })

    old_role = user.role

    # 新增判断：如果新旧角色相同，不做任何操作
    if old_role == role:
        return templates.TemplateResponse("success.html", {
            "request": request,
            "title": "无修改",
            "message": f"用户「{username}」的角色本就是「{old_role}」，无需修改。",
            "redirect_url": "/users",
            "status": "info"
        })

    # 正常执行角色修改
    user.role = role
    db.commit()

    cleanup_messages = []

    # 普通用户升级为 doctor/admin/superadmin → 删除设备
    if old_role == "user" and role in ["doctor", "admin", "superadmin"]:
        deleted_devices = db.query(Device).filter(Device.owner == username).delete()
        db.commit()
        cleanup_messages.append(f"删除设备 {deleted_devices} 台")

    # doctor → admin/superadmin → 解除患者绑定
    elif old_role == "doctor" and role in ["admin", "superadmin"]:
        unbound_count = db.query(models.User).filter(models.User.doctor_id == user.id).update({"doctor_id": None})
        db.commit()
        cleanup_messages.append(f"解除患者绑定 {unbound_count} 个")

    # doctor/admin/superadmin → user → 删除设备 & 清空病人绑定
    elif old_role in ["doctor", "admin", "superadmin"] and role == "user":
        deleted_devices = db.query(Device).filter(Device.owner == username).delete()
        db.commit()
        cleanup_messages.append(f"删除设备 {deleted_devices} 台")
        if old_role == "doctor":
            unbound_count = db.query(models.User).filter(models.User.doctor_id == user.id).update({"doctor_id": None})
            db.commit()
            cleanup_messages.append(f"解除患者绑定 {unbound_count} 个")

    msg_detail = "；".join(cleanup_messages) if cleanup_messages else "无额外操作"
    logger.info(f"{current_name}修改用户{username}的角色修改为{role}")
    return templates.TemplateResponse("success.html", {
        "request": request,
        "title": "修改成功",
        "message": f"已成功将用户「{username}」的角色修改为「{role}」，并执行清理：{msg_detail}。",
        "redirect_url": "/users",
        "status": "success"
    })
# ---------------- 删除用户 ----------------
@router.get("/users/delete/{username}")
def delete_user(username: str, request: Request, db: Session = Depends(get_db)):
    current_name, current_role = get_current_user_info(request)
    if not current_name:
        return RedirectResponse(url="/login", status_code=303)
    if current_role not in ["admin","superadmin"]:
        return RedirectResponse(url=f"/users?msg=permission_denied", status_code=303)
    user = db.query(models.User).filter(models.User.username == username).first()
    if not user:
        return RedirectResponse(url="/users?msg=users_not_exits", status_code=303)
    if user.role == "superadmin":
        return RedirectResponse(url="/users?msg=permission_denied", status_code=303)
    if user.username == current_name:
        return RedirectResponse(url="/users?msg=can_not_delete_yourself", status_code=303)
    if current_role=="admin" and user.role=="admin":
        return RedirectResponse(url="/users?msg=permission_denied", status_code=303)
    db.delete(user)
    db.commit()
    logger.info(f"{current_name}删除用户{username}")
    return RedirectResponse(url="/users?msg=delete_success", status_code=303)
